﻿using AutoMapper;
using wwl.Contract.Dtos.Common;
using wwl.Contract.Dtos.Requests.Rbac;
using wwl.Contract.Dtos.Responses.Rbac;
using wwl.Contract.Interfaces.Rbac;
using wwl.Domain.Entities.Rbac;

namespace wwl.Application.Services.Rbac
{
  /// <summary>
  /// 租户领域服务实现（应用层）
  /// 实现 <see cref="ITenantService"/> 接口，封装租户相关的完整业务流程，协调领域实体与仓储完成核心业务操作
  /// 属于权限模块（Rbac）的核心服务，是前端请求与领域逻辑之间的桥梁
  /// </summary>
  public class TenantService : ITenantService
  {
    /// <summary>
    /// 租户专属仓储（依赖注入，用于数据访问操作）
    /// </summary>
    private readonly ITenantRepository _repository;

    /// <summary>
    /// 对象映射器（依赖注入，用于领域实体与DTO的转换）
    /// </summary>
    private readonly IMapper _mapper;

    /// <summary>
    /// 初始化租户服务（构造函数注入依赖）
    /// </summary>
    /// <param name="repository">租户仓储实例</param>
    /// <param name="mapper">AutoMapper实例</param>
    public TenantService(ITenantRepository repository, IMapper mapper)
    {
      _repository = repository;
      _mapper = mapper;
    }

    /// <summary>
    /// 异步根据ID查询租户详情
    /// </summary>
    /// <param name="id">租户唯一标识</param>
    /// <returns>
    /// 找到则返回租户DTO（<see cref="TenantResponse"/>），未找到则返回null
    /// DTO包含租户的核心业务信息（编码、名称、状态等），适配前端展示需求
    /// </returns>
    /// <remarks>
    /// 业务流程：
    /// 1. 调用仓储查询租户领域实体；
    /// 2. 若实体存在，通过AutoMapper转换为DTO返回；
    /// 3. 若实体不存在，返回null（避免抛出异常，由前端处理“未找到”场景）。
    /// </remarks>
    public async Task<TenantResponse?> GetByIdAsync(string id)
    {
      var entity = await _repository.GetByIdAsync(id);
      return entity == null ? null : _mapper.Map<TenantResponse>(entity);
    }

    /// <summary>
    /// 异步创建租户
    /// </summary>
    /// <param name="request">创建租户的请求参数（包含编码、名称等信息）</param>
    /// <param name="createdBy">创建人标识（如用户ID，用于审计追踪）</param>
    /// <returns>创建成功后的租户DTO（包含自动生成的ID、创建时间等完整信息）</returns>
    /// <exception cref="Exception">当租户编码已存在时抛出异常，阻止重复创建</exception>
    /// <remarks>
    /// 核心业务流程（DDD应用层协调逻辑）：
    /// 1. 校验编码唯一性：调用仓储的 <see cref="ITenantRepository.ExistsByCodeAsync"/> 方法，确保编码未被占用；
    /// 2. 构建领域实体：将请求参数转换为 <see cref="Tenant"/> 领域实体，设置创建人等元数据；
    /// 3. 持久化实体：调用仓储新增方法保存实体到数据库；
    /// 4. 转换返回结果：将新增的实体映射为DTO，返回给前端。
    /// 所有业务规则在此流程中集中执行，确保领域状态一致性。
    /// </remarks>
    public async Task<TenantResponse> CreateAsync(CreateTenantRequest request, string createdBy)
    {
      // 校验租户编码唯一性（核心业务规则）
      if (await _repository.ExistsByCodeAsync(request.TenantCode))
      {
        throw new Exception($"租户编码 '{request.TenantCode}' 已存在");
      }

      // 构建领域实体（封装核心业务状态）
      var entity = new Tenant
      {
        TenantCode = request.TenantCode,
        TenantName = request.TenantName,
        Remarks = request.Remarks!, // 备注可为空，通过!运算符告知编译器已处理null场景（请求模型允许null）
        CreatedBy = createdBy       // 设置创建人，用于审计
      };

      // 调用仓储新增实体（数据持久化）
      var result = await _repository.AddAsync(entity);
      // 转换为DTO返回（隔离领域实体与外部）
      return _mapper.Map<TenantResponse>(result);
    }

    /// <summary>
    /// 异步更新租户信息
    /// </summary>
    /// <param name="id">待更新租户的唯一标识</param>
    /// <param name="request">更新租户的请求参数（包含名称、状态等可修改字段）</param>
    /// <returns>更新后的租户DTO（反映最新状态）</returns>
    /// <exception cref="Exception">当租户不存在或状态无效时抛出异常</exception>
    /// <remarks>
    /// 核心业务流程：
    /// 1. 校验租户存在性：查询租户实体，不存在则抛异常；
    /// 2. 校验状态合法性：将请求中的状态字符串转换为领域枚举，无效则抛异常；
    /// 3. 更新实体状态：修改租户的名称、状态、备注等字段；
    /// 4. 持久化更新：调用仓储更新方法提交变更；
    /// 5. 转换返回结果：将更新后的实体映射为DTO返回。
    /// 体现DDD“应用层协调流程，领域实体承载状态”的思想。
    /// </remarks>
    public async Task<TenantResponse> UpdateAsync(string id, UpdateTenantRequest request)
    {
      // 校验租户是否存在
      var entity = await _repository.GetByIdAsync(id);
      if (entity == null)
      {
        throw new Exception($"租户 '{id}' 未找到");
      }

      // 校验并转换状态（字符串→领域枚举，确保状态合法性）
      if (!Enum.TryParse<TenantStatus>(request.Status, out var status))
      {
        throw new Exception($"无效的租户状态 '{request.Status}'");
      }

      // 更新领域实体的业务字段（状态变更）
      entity.TenantName = request.TenantName;
      entity.Status = status;
      entity.Remarks = request.Remarks!;

      // 调用仓储更新实体
      var result = await _repository.UpdateAsync(entity);
      // 转换为DTO返回
      return _mapper.Map<TenantResponse>(result);
    }

    /// <summary>
    /// 异步逻辑删除租户
    /// </summary>
    /// <param name="id">待删除租户的唯一标识</param>
    /// <returns>删除成功返回true；租户不存在返回false</returns>
    /// <remarks>
    /// 业务逻辑：调用仓储的软删除方法（设置IsDeleted=true），保留历史数据用于审计，
    /// 符合领域层“逻辑删除而非物理删除”的业务规则。
    /// </remarks>
    public async Task<bool> DeleteAsync(string id)
    {
      return await _repository.SoftDeleteAsync(id);
    }

    /// <summary>
    /// 异步执行租户分页查询
    /// </summary>
    /// <param name="request">租户分页查询请求（包含页码、页大小及筛选条件）</param>
    /// <returns>分页结果DTO（<see cref="PagedResult{TenantDto}"/>），包含总条数和当前页DTO列表</returns>
    /// <remarks>
    /// 业务流程：
    /// 1. 调用仓储的租户专属分页查询方法，获取领域实体的分页结果；
    /// 2. 通过AutoMapper将 <see cref="PagedResult{Tenant}"/> 转换为 <see cref="PagedResult{TenantDto}"/>，
    ///    内部依赖 <see cref="PagedResultConverter{Tenant, TenantDto}"/> 处理列表转换；
    /// 3. 返回分页DTO，供前端表格展示。
    /// </remarks>
    public async Task<PagedResult<TenantResponse>> GetPagedAsync(TenantPagedRequest request)
    {
      var result = await _repository.GetPagedAsync(request);
      return _mapper.Map<PagedResult<TenantResponse>>(result);
    }
  }
}